Solutions/Threat Intelligence (NEW)/Analytic Rules/FileHashEntity_DeviceFileEvents_Updated.yaml (38 lines of code) (raw):

id: d6f04915-4471-4cb3-b163-a8b72997cf72 name: TI map File Hash to DeviceFileEvents Event description: | 'Identifies a match in DeviceFileEvents Event data from any FileHash IOC from TI' severity: Medium requiredDataConnectors: - connectorId: MicrosoftThreatProtection dataTypes: - DeviceFileEvents - connectorId: ThreatIntelligence dataTypes: - ThreatIntelligenceIndicator - connectorId: ThreatIntelligenceTaxii dataTypes: - ThreatIntelligenceIndicator - connectorId: MicrosoftDefenderThreatIntelligence dataTypes: - ThreatIntelligenceIndicator queryFrequency: 1h queryPeriod: 14d triggerOperator: gt triggerThreshold: 0 tactics: - CommandAndControl relevantTechniques: - T1071 query: | let dt_lookBack = 1h; let ioc_lookBack = 14d; let DeviceFileEvents_ = (union (DeviceFileEvents | where TimeGenerated > ago(dt_lookBack) | where isnotempty(SHA1) | extend FileHashValue = SHA1), (DeviceFileEvents | where TimeGenerated > ago(dt_lookBack) | where isnotempty(SHA256) | extend FileHashValue = SHA256)); let Hashes = DeviceFileEvents_ | distinct FileHashValue; ThreatIntelIndicators //extract key part of kv pair | extend IndicatorType = replace(@"\[|\]|\""", "", tostring(split(ObservableKey, ":", 0))) | where isnotempty(IndicatorType) and IndicatorType == "file" | extend FileHashType = replace("'", "", substring(ObservableKey, indexof(ObservableKey, "hashes.") + 7, strlen(ObservableKey) - indexof(ObservableKey, "hashes.") - 7)) | extend FileHashValue = toupper(ObservableValue) | extend IndicatorId = tostring(split(Id, "--")[2]) | where isnotempty(FileHashValue) | where TimeGenerated > ago(ioc_lookBack) // | where FileHashValue in (Hashes) | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id | where IsActive == true and ValidUntil > now() | extend Description = tostring(parse_json(Data).description) | where Description !contains_cs "State: inactive;" and Description !contains_cs "State: falsepos;" | project-reorder *, FileHashType, FileHashValue, Type | join kind=innerunique (DeviceFileEvents_) on $left.FileHashValue == $right.FileHashValue | where TimeGenerated < ValidUntil | summarize TimeGenerated = arg_max(TimeGenerated, *) by IndicatorId, DeviceId | extend TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel) | extend Description = tostring(parse_json(Data).description) | extend ActivityGroupNames = extract(@"ActivityGroup:(\S+)", 1, tostring(parse_json(Data).labels)) | project TimeGenerated, TrafficLightProtocolLevel, Description, ActivityGroupNames, IndicatorId, FileHashValue, FileHashType, ValidUntil, Confidence, ActionType, DeviceId, DeviceName, FolderPath, RequestAccountDomain, RequestAccountName, RequestAccountSid, MachineGroup | extend timestamp = TimeGenerated entityMappings: - entityType: Account fieldMappings: - identifier: Name columnName: RequestAccountName - identifier: Sid columnName: RequestAccountSid - identifier: NTDomain columnName: RequestAccountDomain - entityType: FileHash fieldMappings: - identifier: Value columnName: FileHashValue - identifier: Algorithm columnName: FileHashType - entityType: Host fieldMappings: - identifier: HostName columnName: DeviceName version: 1.0.1 kind: Scheduled